package com.xndc.netty.iec104.handler;

import com.xndc.netty.iec104.model.IEC104ControlFrame;
import com.xndc.netty.iec104.model.IEC104Frame;
import com.xndc.netty.iec104.model.IEC104InformationFrame;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.Timer;
import java.util.TimerTask;

/**
 * IEC 104会话管理器
 */
@Slf4j
public class Iec104SessionHandler extends ChannelDuplexHandler {
    
    // 定时器超时设置(毫秒)
    private static final int T1_TIMEOUT = 15000; // APDU确认超时
    private static final int T2_TIMEOUT = 10000; // 无数据发送确认超时
    private static final int T3_TIMEOUT = 20000; // 长时间空闲超时
    
    private Channel channel;
    private short sendSequence = 0;      // 发送序列号(0-32767)
    private short receiveSequence = 0;   // 接收序列号(0-32767)
    private Timer t1Timer;               // APDU确认计时器
    private Timer t2Timer;               // 无数据发送确认计时器
    private Timer t3Timer;               // 长时间空闲计时器
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        this.channel = ctx.channel();
        log.info("IEC 104会话建立: {}", channel.remoteAddress());
        
        // 重置序列号
        sendSequence = 0;
        receiveSequence = 0;
        
        // 启动T3计时器
        startT3Timer(ctx);
        
        ctx.fireChannelActive();
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.info("IEC 104会话关闭: {}", channel.remoteAddress());
        
        // 取消所有计时器
        cancelT1Timer();
        cancelT2Timer();
        cancelT3Timer();
        
        ctx.fireChannelInactive();
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof IEC104Frame) {
            handleFrame(ctx, (IEC104Frame) msg);
        }
        
        ctx.fireChannelRead(msg);
    }
    
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            // 通道空闲时，发送测试帧
            sendTestFrame(ctx);
        }
        
        ctx.fireUserEventTriggered(evt);
    }
    
    /**
     * 处理接收到的帧
     */
    private void handleFrame(ChannelHandlerContext ctx, IEC104Frame frame) {
        if (frame.isControlFrame()) {
            handleControlFrame(ctx, (IEC104ControlFrame) frame);
        } else {
            handleInformationFrame(ctx, (IEC104InformationFrame) frame);
        }
    }
    
    /**
     * 处理控制帧
     */
    private void handleControlFrame(ChannelHandlerContext ctx, IEC104ControlFrame frame) {
        // 重置T3定时器
        resetT3Timer(ctx);
        
        switch (frame.getControlType()) {
            case S_FRAME:
                // 收到S帧，可以取消T1计时器
                cancelT1Timer();
                break;
                
            case STARTDT_ACT:
                // 收到启动激活请求，回复启动确认
                log.info("收到启动请求，回复启动确认");
                sendStartDtCon(ctx);
                break;
                
            case STOPDT_ACT:
                // 收到停止激活请求，回复停止确认
                log.info("收到停止请求，回复停止确认");
                sendStopDtCon(ctx);
                break;
                
            case TESTFR_ACT:
                // 收到测试激活请求，回复测试确认
                log.debug("收到测试请求，回复测试确认");
                sendTestFrCon(ctx);
                break;
                
            default:
                // 其他控制帧(确认帧)不需要特殊处理
                break;
        }
    }
    
    /**
     * 处理信息帧
     */
    private void handleInformationFrame(ChannelHandlerContext ctx, IEC104InformationFrame frame) {
        // 检查接收序列号
        short rxSeq = frame.getSendSequence();
        if (rxSeq == receiveSequence) {
            // 序列号正确，增加接收计数
            receiveSequence = (short)((receiveSequence + 1) % 32768);
            
            // 重置定时器
            resetT3Timer(ctx);
            startT2Timer(ctx);
        } else {
            // 序列号错误，可能需要请求重传
            log.warn("序列号错误: 收到={}, 期望={}", rxSeq, receiveSequence);
        }
    }
    
    /**
     * 发送启动确认帧
     */
    private void sendStartDtCon(ChannelHandlerContext ctx) {
        IEC104ControlFrame frame = new IEC104ControlFrame();
        frame.setControlType(IEC104ControlFrame.ControlType.STARTDT_CON);
        ctx.writeAndFlush(frame);
    }
    
    /**
     * 发送停止确认帧
     */
    private void sendStopDtCon(ChannelHandlerContext ctx) {
        IEC104ControlFrame frame = new IEC104ControlFrame();
        frame.setControlType(IEC104ControlFrame.ControlType.STOPDT_CON);
        ctx.writeAndFlush(frame);
    }
    
    /**
     * 发送测试确认帧
     */
    private void sendTestFrCon(ChannelHandlerContext ctx) {
        IEC104ControlFrame frame = new IEC104ControlFrame();
        frame.setControlType(IEC104ControlFrame.ControlType.TESTFR_CON);
        ctx.writeAndFlush(frame);
    }
    
    /**
     * 发送测试帧
     */
    private void sendTestFrame(ChannelHandlerContext ctx) {
        log.debug("发送测试帧");
        IEC104ControlFrame frame = new IEC104ControlFrame();
        frame.setControlType(IEC104ControlFrame.ControlType.TESTFR_ACT);
        ctx.writeAndFlush(frame);
    }
    
    /**
     * 发送S帧
     */
    private void sendSFrame(ChannelHandlerContext ctx) {
        log.debug("发送S帧确认");
        IEC104ControlFrame frame = new IEC104ControlFrame();
        frame.setControlType(IEC104ControlFrame.ControlType.S_FRAME);
        frame.setReceiveSequence(receiveSequence);
        ctx.writeAndFlush(frame);
    }
    
    /**
     * 启动T1计时器
     */
    private void startT1Timer(ChannelHandlerContext ctx) {
        cancelT1Timer();
        t1Timer = new Timer();
        t1Timer.schedule(new TimerTask() {
            @Override
            public void run() {
                log.warn("T1定时器超时，未收到确认");
                // 这里可以实现帧重传逻辑
            }
        }, T1_TIMEOUT);
    }
    
    /**
     * 启动T2计时器
     */
    private void startT2Timer(ChannelHandlerContext ctx) {
        cancelT2Timer();
        t2Timer = new Timer();
        t2Timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // T2超时，发送S帧
                sendSFrame(ctx);
            }
        }, T2_TIMEOUT);
    }
    
    /**
     * 启动/重置T3计时器
     */
    private void startT3Timer(ChannelHandlerContext ctx) {
        cancelT3Timer();
        t3Timer = new Timer();
        t3Timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // T3超时，发送测试帧
                sendTestFrame(ctx);
            }
        }, T3_TIMEOUT, T3_TIMEOUT);
    }
    
    /**
     * 重置T3计时器
     */
    private void resetT3Timer(ChannelHandlerContext ctx) {
        startT3Timer(ctx);
    }
    
    /**
     * 取消T1计时器
     */
    private void cancelT1Timer() {
        if (t1Timer != null) {
            t1Timer.cancel();
            t1Timer = null;
        }
    }
    
    /**
     * 取消T2计时器
     */
    private void cancelT2Timer() {
        if (t2Timer != null) {
            t2Timer.cancel();
            t2Timer = null;
        }
    }
    
    /**
     * 取消T3计时器
     */
    private void cancelT3Timer() {
        if (t3Timer != null) {
            t3Timer.cancel();
            t3Timer = null;
        }
    }
    
    /**
     * 获取并递增发送序列号
     */
    public short getNextSendSequence() {
        short seq = sendSequence;
        sendSequence = (short)((sendSequence + 1) % 32768);
        return seq;
    }
} 